#include <string.h>
#include "hj212_client.h"
#include "hj212_msg.h"
#include "hj212_client_ops.h"
#include "hj212_pack.h"
#include "hj212_data_msg/hj212_data_msg.h"

struct datamsg_type
{
    int (*pack)(struct hj212_datamsg *msg, int protocol,        // 打包函数
                struct timeval precise_time, int item_maxlen,
                char *buffer, int len);
    int cn;                                                     // 类型对应的cn
    const char *cn_name;                                        // 中文名
    int response_cn;                                            // 响应CN
    int typesize;                                               // item的size
    int item_maxnum_per_package;                                // 一个包最多几个item
};
static const struct datamsg_type datamsg_table[HJ212_MSG_TYPE_NUM] =
{
    [HJ212_MSG_TYPE_RTD] =
    {
        .pack = hj212_datamsg_pack_rtdata,
        .cn = HJ_CMD_RTD_DATA_2011,
        .cn_name = "实时数据2011",
        .response_cn = HJ_CMD_GET_DATARTN_9014,
        .typesize = sizeof(struct pol_rtval),
        .item_maxnum_per_package = HJ212_POL_MAXNUM_IN_RTDATA,
    },
    [HJ212_MSG_TYPE_MIN] =
    {
        .pack = hj212_datamsg_pack_hisdata,
        .cn = HJ_CMD_MIN_DATA_2051,
        .cn_name = "分钟数据2051",
        .response_cn = HJ_CMD_GET_DATARTN_9014,
        .typesize = sizeof(struct pol_his_data),
        .item_maxnum_per_package = HJ212_POL_MAXNUM_IN_HISDATA,
    },
    [HJ212_MSG_TYPE_HOUR] =
    {
        .pack = hj212_datamsg_pack_hisdata,
        .cn = HJ_CMD_HOUR_DATA_2061,
        .cn_name = "小时数据2061",
        .response_cn = HJ_CMD_GET_DATARTN_9014,
        .typesize = sizeof(struct pol_his_data),
        .item_maxnum_per_package = HJ212_POL_MAXNUM_IN_HISDATA,
    },
    [HJ212_MSG_TYPE_DAY] =
    {
        .pack = hj212_datamsg_pack_hisdata,
        .cn = HJ_CMD_DAY_DATA_2031,
        .cn_name = "日数据2031",
        .response_cn = HJ_CMD_GET_DATARTN_9014,
        .typesize = sizeof(struct pol_his_data),
        .item_maxnum_per_package = HJ212_POL_MAXNUM_IN_HISDATA,
    },
    [HJ212_MSG_TYPE_POLSTETE] = 
    {
        .pack = hj212_datamsg_pack_polstate,
        .cn = HJ_CMD_GET_INFO_3020,
        .cn_name = "3020",
        .response_cn = HJ_CMD_GET_DATARTN_9014,
        .typesize = sizeof(struct pol_state),
        .item_maxnum_per_package = HJ212_POLSTATE_MAXNUM_IN_POLSTATE,
    }
};

int hj212_datamsg_typesize(int type)
{
    if (type >= HJ212_MSG_TYPE_RTD && type < HJ212_MSG_TYPE_NUM)
    {
        return datamsg_table[type].typesize;
    }
    return -1;
}

int hj212_datamsg_item_maxnum_per_package(int type)
{
    if (type >= HJ212_MSG_TYPE_RTD && type < HJ212_MSG_TYPE_NUM)
    {
        return datamsg_table[type].item_maxnum_per_package;
    }
    return 0;
}

int hj212_datamsg_init(struct hj212_datamsg *msg, int type, void *mempool, int memsize)
{
    if (msg->type >= HJ212_MSG_TYPE_RTD && msg->type < HJ212_MSG_TYPE_NUM)
    {
        memset(msg, 0, sizeof(*msg));
        msg->type = type;
        gen_blk_queue_init(&msg->queue, mempool, datamsg_table[type].typesize, memsize);
        return 0;
    }
    return -1;
}

int hj212_datamsg_pack(struct hj212_datamsg *msg, int protocol, struct timeval precise_time, int item_maxlen, char *buffer, int len)
{
    if (msg->type >= HJ212_MSG_TYPE_RTD && msg->type < HJ212_MSG_TYPE_NUM)
    {
        return datamsg_table[msg->type].pack(msg, protocol, precise_time, item_maxlen, buffer, len);
    }
    return -1;
}

int hj212_datamsg_cn(int type)
{
    if (type >= HJ212_MSG_TYPE_RTD && type < HJ212_MSG_TYPE_NUM)
    {
        return datamsg_table[type].cn;
    }
    return -1;
}

const char *hj212_datamsg_cn_to_name(int cn)
{
    for(int i = 0; i < HJ212_MSG_TYPE_NUM; i++)
    {
        if(datamsg_table[i].cn == cn)
        {
            return datamsg_table[i].cn_name;
        }
    }
    return NULL;
}

int hj212_datamsg_response_cn(int type)
{
    if (type >= HJ212_MSG_TYPE_RTD && type < HJ212_MSG_TYPE_NUM)
    {
        return datamsg_table[type].response_cn;
    }
    return -1;
}

int hj212_datamsg_cn_to_type(int cn)
{
    for (int type = HJ212_MSG_TYPE_RTD; type < HJ212_MSG_TYPE_NUM; type++)
    {
        if (cn == datamsg_table[type].cn)
        {
            return type;
        }
    }
    return -1;
}

int hj212_response_is_idle(struct hj212_response *response)
{
    return response->state == HJ212_RESPONSE_IDLE;
}

void hj212_response_init(struct hj212_response *response,
                         hj212_response_match_t match, void *match_param,
                         hj212_response_timeout_t timeout_handle, void *timeout_param)
{
    response->state = HJ212_RESPONSE_IDLE;
    response->match = match;
    response->match_param = match_param;
    response->timeout_handle = timeout_handle;
    response->timeout_param = timeout_param;
    rt_list_init(&response->list);
}

void hj212_response_register(struct hj212_client *client, struct hj212_response *response, int timeout)
{
    response->state = HJ212_RESPONSE_WAITINT;
    response->register_time = hj212_client_current_timestamp(client);
    response->timeout = timeout;
    rt_list_remove(&response->list);
    rt_list_insert_before(&client->response_list, &response->list);
}

void hj212_response_unregister(struct hj212_response *response)
{
    rt_list_remove(&response->list);
    response->state = HJ212_RESPONSE_IDLE;
}

void hj212_response_register_default(struct hj212_client *client, struct hj212_response *response, int timeout, int cn, const char *qn)
{
    response->cn = cn;
    strncpy(response->qn, qn, HJ212_QN_MAX_LEN);
    hj212_response_register(client, response, timeout);
}

void hj212_pack_local_head(struct hj212_client *client, char *buffer, int bufferlen, const char *qn, const char *syscode, int cn, int isresponse, struct hj212_msg *result)
{
    struct hj212_msg msg;
    /* 准备数据 */
    msg.flag = HJ_FLAG_NO_PACK_PNUM;
    if (isresponse)
        msg.flag |= HJ_FLAG_NO_RESPONSE;
    int protocol = HJ212_PROTOCOL_2017;
    hj212_client_command(client, GET_HJ212_PROTOCOL, &protocol);
    msg.flag |= protocol == HJ212_PROTOCOL_2017 ?
                HJ_FLAG_HJ212_2017 : HJ_FLAG_HJ212_2005;
    if (protocol == HJ212_PROTOCOL_2017)
    {
        hj212_generate_qn(msg.qn, sizeof(msg.qn), hj212_client_current_subsec(client));
        qn = msg.qn;
    }
    msg.cn = cn;
    hj212_client_command(client, GET_HJ212_ACCESS_PWD, msg.access_pwd);
    hj212_client_command(client, GET_HJ212_CLIENT_MN, msg.mn);

    if (!syscode)
    {
        hj212_client_command(client, GET_HJ212_SYS_CODE, msg.st);
    }
    else
    {
        strncpy(msg.st, syscode, HJ212_SYSCODE_MAX_LEN);
    }

    /* 打包 */
    if (protocol == HJ212_PROTOCOL_2017 || !qn)
    {
        hj212_pack_head(qn, msg.st, msg.cn, msg.access_pwd, msg.mn, msg.flag, buffer, bufferlen);
    }
    else
    {
        hj212_pack_head(NULL, msg.st, msg.cn, msg.access_pwd, msg.mn, msg.flag, buffer, bufferlen);
        hj212_pack_add_field((char *)buffer, bufferlen, "Qn=%s;", qn);
    }
    if (result)
        memcpy(result, &msg, sizeof(msg));
}

void hj212_pack_local(struct hj212_client *client,
                      char *buffer, int bufferlen,
                      const char *qn, const char *syscode, int cn, int isresponse,
                      struct hj212_msg *result,
                      const char *format, ...)
{
    hj212_pack_local_head(client, buffer, bufferlen, qn, syscode, cn, isresponse, result);
    va_list ap;
    va_start(ap, format);
    _hj212_pack_add_field(buffer, bufferlen, format, ap);
    va_end(ap);
    hj212_pack_end(buffer, bufferlen);
}

int hj212_send_local_pack(struct hj212_client *client,
                          const char *qn, const char *syscode, int cn, int isresponse,
                          struct hj212_msg *result,
                          const char *format, ...)
{
    struct send_buffer *buffer = hj212_acquire_sendbuf(client);
    if (!buffer)
    {
        return -1;
    }

    hj212_pack_local_head(client, buffer->mempool, HJ212_PACK_MAX_SIZE, qn, syscode, cn, isresponse, result);
    if (format != NULL)
    {
        va_list ap;
        va_start(ap, format);
        _hj212_pack_add_field(buffer->mempool, HJ212_PACK_MAX_SIZE, format, ap);
        va_end(ap);
    }
    hj212_pack_end(buffer->mempool, HJ212_PACK_MAX_SIZE);

    /* 追加到发送链表 */
    hj212_append_sendbuf(client, buffer, NULL, NULL);
    return 0;
}
